package Objets;

import java.io.IOException;
import java.io.StringWriter;
import java.util.Date;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.jxta.credential.AuthenticationCredential;
import net.jxta.credential.Credential;
import net.jxta.document.MimeMediaType;
import net.jxta.document.StructuredDocument;
import net.jxta.document.StructuredTextDocument;
import net.jxta.endpoint.Message;
import net.jxta.endpoint.Message.ElementIterator;
import net.jxta.endpoint.MessageElement;
import net.jxta.endpoint.StringMessageElement;
import net.jxta.impl.endpoint.WireFormatMessage;
import net.jxta.impl.endpoint.WireFormatMessageFactory;
import net.jxta.membership.MembershipService;
import net.jxta.peergroup.PeerGroup;
import net.jxta.pipe.*;
import net.jxta.protocol.PipeAdvertisement;
import net.jxta.util.CountingOutputStream;
import net.jxta.util.DevNullOutputStream;

/**
 *
 * @author Nono
 */
public class Pair implements OutputPipeListener, PipeMsgListener {

    protected String nom;
    /*
     * Pipe privé pour communication point à point
     */
    protected PipeService privatePipe;
    protected PipeAdvertisement privatePipeAdv;
    protected InputPipe privatePipeIn = null;
    /*
     * Pipe publique pour communication à tous les membres du groupe
     */
    protected PipeService groupePipe;
    protected PipeAdvertisement groupePipeAdv;
    protected InputPipe groupePipeIn = null;
    private String messageSend;

    public Pair() {
        this.nom = "";
    }

    public Pair(String nom) {
        this.nom = nom;
    }

    public PipeService getGroupePipe() {
        return groupePipe;
    }

    public void setGroupePipe(PipeService groupePipe) {
        this.groupePipe = groupePipe;
    }

    public PipeAdvertisement getGroupePipeAdv() {
        return groupePipeAdv;
    }

    public void setGroupePipeAdv(PipeAdvertisement groupePipeAdv) {
        this.groupePipeAdv = groupePipeAdv;
    }

    public InputPipe getGroupePipeIn() {
        return groupePipeIn;
    }

    public void setGroupePipeIn(InputPipe groupePipeIn) {
        this.groupePipeIn = groupePipeIn;
    }

    public String getNom() {
        return nom;
    }

    public void setNom(String nom) {
        this.nom = nom;
    }

    public PipeService getPrivatePipe() {
        return privatePipe;
    }

    public void setPrivatePipe(PipeService privatePipe) {
        this.privatePipe = privatePipe;
    }

    public PipeAdvertisement getPrivatePipeAdv() {
        return privatePipeAdv;
    }

    public void setPrivatePipeAdv(PipeAdvertisement privatePipeAdv) {
        this.privatePipeAdv = privatePipeAdv;
    }

    public InputPipe getPrivatePipeIn() {
        return privatePipeIn;
    }

    public void setPrivatePipeIn(InputPipe privatePipeIn) {
        this.privatePipeIn = privatePipeIn;
    }

    public String getMessageSend() {
        return messageSend;
    }

    public void setMessageSend(String messageSend) {
        this.messageSend = messageSend;
    }

    @Override
    public void pipeMsgEvent(PipeMsgEvent event) {
        /*if (event.getPipeID() == privatePipeIn.getPipeID()) {
            System.out.println("Je reçoit sur mon pipe privé");
        }
        if (event.getPipeID() == groupePipeIn.getPipeID()) {
            System.out.println("Je reçoit sur mon pipe de groupe");
        }*/
        Message msg = null;
        try {
            // grab the message from the event
            msg = event.getMessage();
            String msgContent = "";
            Message.ElementIterator it = msg.getMessageElements();
            System.out.println("---------------Message Receive---------------------");
            while (it.hasNext()) {
                MessageElement el = (MessageElement) it.next();
                msgContent = el.getElementName();
                System.out.println("Message : " + msgContent);
            }
            System.out.println("-------------------End of Message---------------------");
            if (msg == null) {
                return;
            }
            String tmp [] = msgContent.split(" ");
            if(!tmp[0].equals("repgroupe") && !tmp[0].equals(nom)){
                System.out.println("-------------Group Message Receive---------------------");
                System.out.println("Message : " + msgContent);
                System.out.println("-------------------End of Message---------------------");
            }
            //printMessageStats(msg, true);
        } catch (Exception e) {
            e.printStackTrace();
            return;
        }
    }

    protected void printMessageStats(Message msg, boolean verbose) {
        try {
            CountingOutputStream cnt;
            ElementIterator it = msg.getMessageElements();
            System.out.println("------------------Begin Message---------------------");
            WireFormatMessage serialed = WireFormatMessageFactory.toWire(
                    msg,
                    new MimeMediaType("application/x-jxta-msg"), (MimeMediaType[]) null);
            System.out.println("Message Size :" + serialed.getByteLength());
            while (it.hasNext()) {
                MessageElement el = (MessageElement) it.next();
                String eName = el.getElementName();
                cnt = new CountingOutputStream(new DevNullOutputStream());
                el.sendToStream(cnt);
                long size = cnt.getBytesWritten();
                System.out.println("Element " + eName + " : " + size);
                if (verbose) {
                    System.out.println("[" + el + "]");
                }
            }
            System.out.println("-------------------End Message----------------------");
        } catch (Exception e) {
            e.printStackTrace();

        }
    }

    public void run() {

        try {
            privatePipeIn = privatePipe.createInputPipe(privatePipeAdv, this);
        } catch (Exception e) {
            return;
        }
        if (privatePipeIn == null) {
            System.out.println(" cannot open private InputPipe");
            System.exit(-1);
        }

        try {
            groupePipeIn = groupePipe.createInputPipe(groupePipeAdv, this);
        } catch (Exception e) {
            System.out.println("Catch group");
            return;
        }
        if (groupePipeIn == null) {
            System.out.println(" cannot open groupe InputPipe");
            System.exit(-1);
        }

        String commande = "";
        Scanner in = new Scanner(System.in);
        System.out.print("Veuillez entrer une commande (ajouter, rechercher, bannir , debannir (uniquement pour admin) : ");
        while (!(commande.equals("fin"))) {
            commande = in.nextLine();
            traitement(commande);
        }
        in.close();
    }

    public void joinGroup(PeerGroup grp) {
        StructuredDocument creds = null;
        try {
            // Generate the credentials for the Peer Group
            AuthenticationCredential authCred = new AuthenticationCredential(grp, null, creds);

            // Get the MembershipService from the peer group
            MembershipService membership = grp.getMembershipService();

            // Get the Authenticator from the Authentication creds
            net.jxta.membership.Authenticator auth = membership.apply(authCred);

            // Check if everything is okay to join the group
            if (auth.isReadyForJoin()) {
                Credential myCred = membership.join(auth);

                System.out.println("Successfully joined group "
                        + grp.getPeerGroupName());

                // display the credential as a plain text document.
                
                StructuredTextDocument doc = (StructuredTextDocument) myCred.getDocument(new MimeMediaType("text/plain"));

                StringWriter out = new StringWriter();
                doc.sendToWriter(out);

                out.close();
            } else {
                System.out.println("Failure: unable to join group");
            }
        } catch (Exception e) {
            System.out.println("Failure in authentication.");
            e.printStackTrace();
        }
    }

    private void traitement(String commande) {
        String str[] = commande.split(" ");
        System.out.println("Commande lancée : " + str[0]);
        if (str[0].equals("bannir")) {
            envoie("bannir", str[1]);
        } else if (str[0].equals("debannir")) {
            envoie("debannir", str[1]);
        } else if (str[0].equals("chercher")) {
            envoie("chercher", str[1]);
        } else if (str[0].equals("ajouter")) {
            envoie("ajouter", str[1]);
        }
    }

    private void envoie(String commande, String arg) {
        messageSend = nom + " " + commande + " " + arg;
        try {
            groupePipe.createOutputPipe(groupePipeAdv, this);
        } catch (IOException ex) {
            Logger.getLogger(SuperPair.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    @Override
    public void outputPipeEvent(OutputPipeEvent event) {
        OutputPipe op = event.getOutputPipe();
        Message msg = null;

        try {
            msg = new Message();
            Date date = new Date(System.currentTimeMillis());
            StringMessageElement sme = new StringMessageElement(this.getMessageSend(), date.toString(), null);;
            msg.addMessageElement(null, sme);
            op.send(msg);
        } catch (IOException e) {
            System.out.println("failed to send message");
            e.printStackTrace();
            System.exit(-1);
        }
        op.close();
    }
}
